#include "memory_pool.h"
#include "video_base.h"

#define LOG printf

namespace video
{


IMemoryPool *IMemoryPool::getInstance(){
    static MemoryPoolImpl ins;
    return &ins;
}


MemoryPoolImpl::MemoryPoolImpl(/* args */){


}

MemoryPoolImpl::~MemoryPoolImpl(){


}

int32_t MemoryPoolImpl::createSolt( int32_t *solt_id, int32_t w, int32_t h, int32_t w_stride, int32_t h_stride, int32_t frame_type, int32_t max_num ){

    //从bitmap中找到一个位置
    int32_t slot_id = find_fist_zero_solt();
    if( slot_id < 0 ){
        return -1;
    }

    //创建一个slot,用于管理同一类型的IMemory
    MemorySolt *mem_slot = new MemorySolt();
    mem_slot->id = slot_id;
    mem_slot->solt_type =  SOLT_TYPE_VIDEO;
    mem_slot->acture_size = 0;
    mem_slot->max_size = max_num;
    mem_slot->u.video.width = w;
    mem_slot->u.video.height = h;
    mem_slot->u.video.width_stride = w_stride;
    mem_slot->u.video.height_stride = h_stride;
    mem_slot->u.video.frame_type = frame_type;
    //将Solt依据bitmap得出的序列号一次存在在map中
    _solts[slot_id] = mem_slot;
    _solts_bm.set(slot_id, true);
    *solt_id = slot_id;

    return 0;
}

int32_t MemoryPoolImpl::createSolt( int32_t *solt_id, int32_t buf_size, int32_t frame_type, int32_t max_num ){

    //从bitmap中找到一个位置
    int32_t slot_id = find_fist_zero_solt();
    if( slot_id < 0 ){
        return -1;
    }

    //创建一个slot,用于管理同一类型的IMemory
    MemorySolt *mem_slot = new MemorySolt();
    mem_slot->id = slot_id;
    mem_slot->solt_type = SOLT_TYPE_BUFFER;
    mem_slot->acture_size = 0;
    mem_slot->max_size = max_num;
    mem_slot->u.buffer.size = buf_size;
    //将Solt依据bitmap得出的序列号一次存在在map中
    _solts[slot_id] = mem_slot;
    _solts_bm.set(slot_id, true);
    *solt_id = slot_id;

    return 0;
}

int32_t MemoryPoolImpl::destorySolt(int32_t solt_id){

    //依据solt_id，从map中找到要销毁的Solt
    std::map<int32_t, MemorySolt*>::iterator it = _solts.find(solt_id);
    if( it ==  _solts.end()){
        return -1;
    }

    //判断Solt中的数据帧是否全部释放
    MemorySolt *mem_slot = it->second;
    if( mem_slot->mem.size() != mem_slot->mem_free.size()){
        LOG( "Not all mem release !!!\r\n" );
        abort();
        return -2;
    }

    //释放Solt中所有数据帧的地址
    std::vector<IMemory*>::iterator mem_it = mem_slot->mem.begin();
    while( mem_it != mem_slot->mem.end()) {
        IMemory *pMem = *mem_it;
        mem_slot->mem.erase(mem_it);
        pMem->deallocate();
        delete pMem;
        mem_it = mem_slot->mem.begin();
    }

    //从map中清除该Solt
    _solts.erase(it);
    delete mem_slot;

    //将bitmap对应位重置
    _solts_bm.reset( solt_id );

    return 0;
}

//从指定Solt中获取一个帧
IMemory *MemoryPoolImpl::get(int32_t solt_id){

    //依据solt_id，从map中找到要获取的Solt
    IMemory *pMem = NULL;
    std::map<int32_t, MemorySolt*>::iterator it = _solts.find(solt_id);

    if( it ==  _solts.end()){
        return NULL;
    }

    MemorySolt* pSolt = it->second;
    if( pSolt == NULL ){
        return NULL;
    }
    //检查Solt中是否有现成的IMemeory,有就直接返回。
    if( pSolt->mem_free.size() > 0 ){
        pMem = pSolt->mem_free.front();
        pSolt->mem_free.pop_front();
        pSolt->mem_used.push_back(pMem);
        pMem->add_ref();
        return pMem;
    }

    //检查该Solt中帧个数是否超标
    if( pSolt->acture_size > pSolt->max_size ){
        return NULL;
    }

    if( pSolt->solt_type == SOLT_TYPE_VIDEO ){
        //创建一个新的帧
        pMem = new Video_Frame( pSolt->u.video.frame_type,
                                pSolt->u.video.timestamp,
                                pSolt->u.video.width,
                                pSolt->u.video.height,
                                pSolt->u.video.width_stride,
                                pSolt->u.video.height_stride );
    }
    else if( pSolt->solt_type == SOLT_TYPE_BUFFER ){
        pMem = new Buffer_Frame( pSolt->u.buffer.type,
                                 pSolt->u.buffer.timestamp,
                                 pSolt->u.buffer.size);

    }



    pMem->allocate(NULL, 0);

    ++pSolt->acture_size;
    pSolt->mem.push_back( pMem );
    pSolt->mem_used.push_back( pMem );

    pMem->set_mgr( this, (void *)pSolt );

    pMem->add_ref();
    return pMem;
}

void MemoryPoolImpl::signal_mem_release( IMemory *mem, void *ctx ){
    MemorySolt *pSolt = (MemorySolt *)ctx;
    int32_t solt_id = pSolt->id;
    put( solt_id, mem );
}

//释放一个帧
bool MemoryPoolImpl::put( int32_t solt_id, IMemory *mem){

    std::map<int32_t, MemorySolt*>::iterator it = _solts.find(solt_id);
    if( it ==  _solts.end()){
        return false;
    }

    MemorySolt *pSolt = it->second;

    std::list<IMemory*>::iterator mem_used_it = pSolt->mem_used.begin();
    while( mem_used_it != pSolt->mem_used.end() ){
        if( mem == *mem_used_it )
            break;
        mem_used_it++;
    }

    if( mem_used_it == pSolt->mem_used.end() ){
        return false;
    }

    pSolt->mem_used.erase( mem_used_it );
    pSolt->mem_free.push_back( mem );

    return true;

}

int32_t MemoryPoolImpl::find_fist_zero_solt(){

    for( int32_t i = 0; i < _solts_bm.size(); ++i ){
        if(_solts_bm.test(i) == false){
            return i;
        }
    }

    return -1;
}

} // namespace video